/*
 *  CEScrollView.cpp
 *  LID Library
 *
 *  Created by Alexander Trutchenko on 09/11/11.
 *  Copyright 2011 League of Independent Developers. All rights reserved.
 *
 */

#include "cocos2dx_extentions/controls/CEScrollView.h"

#include "cocos2dx_extentions/controls/CEScrollBar.h"
#include "cocos2dx_extentions/utility/CECocos2dUtility.h"

using namespace cocos2d;

namespace cocosext {

#define CE_SCROLLVIEW_RUBBER_UPDATE_POS_K 0.25f 

/////////////////////////////////////////////////////
//
/** CEScrollView 
* 
*/
/////////////////////////////////////////////////////

CEScrollView* CEScrollView::node(cocos2d::CCNode* scrollableArea,
								 cocos2d::CCNode* background,
								 bool horizontalScrolling,
								 CEScrollBar* horizontalScrollBar,
								 bool verticalScrolling,
								 CEScrollBar* verticalScrollBar,
								 bool insideScrollbar,
								 bool hiddenScrollbar)
{
	CEScrollView *pRet = new CEScrollView(horizontalScrolling,
										  verticalScrolling,
										  insideScrollbar,
										  hiddenScrollbar);
	CCAssert(pRet != NULL, NULL);
	if (pRet->init(scrollableArea,
				   background,
				   horizontalScrollBar,
				   verticalScrollBar))
	{
		pRet->autorelease();
        return pRet;
	}
	else
	{
		CC_SAFE_DELETE(pRet)
		return NULL;
	}
}

/////////////////////////////////////////////////////
//
CEScrollView::CEScrollView(bool horizontalScrolling,
						   bool verticalScrolling,
						   bool insideScrollbar,
						   bool hiddenScrollbar)
: _scrollableArea(NULL)
, _frame(NULL)
, _saaX(eCE_SAA_X_center)
, _saaY(eCE_SAA_Y_center)
, _background(NULL)
, _horizontalScrolling(horizontalScrolling)
, _horizontalScrollBar(NULL)
, _verticalScrolling(verticalScrolling)
, _verticalScrollBar(NULL)
, _insideScrollbar(insideScrollbar)
, _hiddenScrollbar(hiddenScrollbar)
, _areScrollBarsShown(false)
, _touchPriority(kCCMenuTouchPriority)
, _currentTouch(NULL)
, _touchBeginPoint(CCPointZero)
, _latestTouchMovePoint(CCPointZero)
, _isMovedOnLatestTouchMove(false)
, _latestTime(0.f)
, _touchBeginTime(0.f)
, _touchEndTime(0.f)
, _startPoint(CCPointZero)
, _accumulatedTime(0.f)
, _speedVector(CCPointZero)
, _accelVector(CCPointZero)
, _accumulatorCursor(0)
, _isSelfMoving(false)
, _disableCount(0)
{
	for (unsigned int i = 0; i < CE_SCROLLVIEW_MOVE_FILTER_SIZE; ++i)
	{
		_speedAccumulator[i].x = 0;
		_speedAccumulator[i].y = 0;
	}
}

bool CEScrollView::init(cocos2d::CCNode* scrollableArea,
						cocos2d::CCNode* background,
						CEScrollBar* horizontalScrollBar,
						CEScrollBar* verticalScrollBar)
{
    if (!CCLayer::init())
        return false;

	CCLayer::setIsTouchEnabled(false);
    CCLayer::setIsTouchEnabled(true);

	_scrollableArea = scrollableArea;
	_background = background;
	_horizontalScrollBar = horizontalScrollBar;
	_verticalScrollBar = verticalScrollBar;


//Back
	if (_background != NULL)
	{
		_background->setPosition(CCPointZero);
		_background->setAnchorPoint(CCPointZero);
		_background->setContentSize(this->getContentSize());
		_background->setIsRelativeAnchorPoint(true);
		this->addChild(_background, INT_MIN);
	}
//Frame
	_frame = CENodeScissored<CCNode>::node();
	_frame->setAnchorPoint(CCPointZero);
	if (_insideScrollbar)
	{
		_frame->setContentSize(this->getContentSize());
		_frame->setPosition(CCPointZero);
	}
	else
	{
		CCPoint pt = CCPointZero;
		CCSize sz = this->getContentSize();
		if (_horizontalScrolling)
		{
			if (_horizontalScrollBar != NULL)
			{
				sz.height -= _horizontalScrollBar->getContentSize().width;
				pt.y = _horizontalScrollBar->getContentSize().width;
			}
		}
		if (_verticalScrolling && _verticalScrollBar != NULL)
			sz.width -= _verticalScrollBar->getContentSize().width;
		_frame->setContentSize(sz);
		_frame->setPosition(pt);
	}
	this->addChild(_frame, INT_MIN);

//Scrollable area
	_scrollableArea->setPosition(ccpMid(_frame->getContentSize()));
	_scrollableArea->setAnchorPoint(ccp(0.5f, 0.5f));
	_scrollableArea->setIsRelativeAnchorPoint(true);
	_frame->addChild(_scrollableArea);

//Horisontal scrolling
	if (_horizontalScrolling && _horizontalScrollBar != NULL)
	{
		_horizontalScrollBar->setAnchorPoint(CCPointZero);
		_horizontalScrollBar->setRotation(90);
		_horizontalScrollBar->setPosition(ccp(0, _horizontalScrollBar->getContentSize().width));
		_horizontalScrollBar->setContentSize(CCSize(_horizontalScrollBar->getContentSize().width, this->getContentSize().width));
		if (_frame->getContentSize().width > 0.f)
			_horizontalScrollBar->setBarSize(_scrollableArea->getContentSize().width/_frame->getContentSize().width);
		this->addChild(_horizontalScrollBar);
		if (_hiddenScrollbar)
			_horizontalScrollBar->forceHide();
	}

//Vertical scrolling
	if (_verticalScrolling && _verticalScrollBar != NULL)
	{
		_verticalScrollBar->setAnchorPoint(CCPointZero);
		_verticalScrollBar->setPosition(ccp(this->getContentSize().width - _verticalScrollBar->getContentSize().width, 0));
		_verticalScrollBar->setContentSize(CCSize(_verticalScrollBar->getContentSize().width, this->getContentSize().height));
		if (_frame->getContentSize().height > 0.f)
			_verticalScrollBar->setBarSize(_scrollableArea->getContentSize().height/_frame->getContentSize().height);
		this->addChild(_verticalScrollBar);
		if (_hiddenScrollbar)
			_verticalScrollBar->forceHide();
	}

//Start timer
	this->schedule(schedule_selector(CEScrollView::updateTime));

	return true;
}


/////////////////////////////////////////////////////
// Main interface

void CEScrollView::setIsEnabled(bool isEnabled)
{
	if (isEnabled)
	{
		if(_disableCount == 0)
			return;
		--_disableCount;
		if (_disableCount == 0)
			doSetIsEnabled(isEnabled);
	}
	else
	{
		if (_disableCount == 0)
			doSetIsEnabled(isEnabled);
		++_disableCount;
	}	
}

void CEScrollView::setRelativeScrollableAreaPosition(CCPoint pos)
{
	CCPoint newPos = _scrollableArea->getPosition();
	CCSize frameSz = _frame->getContentSize();
	CCSize sz = _scrollableArea->getContentSize();
	if (!(pos.x < 0.f) && _horizontalScrolling && sz.width > frameSz.width)
	{
		if (pos.x > 1.f)
			pos.x = 1.f;
		else if (pos.x < 0.f)
			pos.x = 0.f;
		newPos.x = sz.width/2.f - (sz.width - frameSz.width)*pos.x;
	}
	if (!(pos.y < 0.f) && _verticalScrolling && sz.height > frameSz.height)
	{
		if (pos.y > 1.f)
			pos.y = 1.f;
		else if (pos.y < 0.f)
			pos.y = 0.f;
		newPos.y = sz.height/2.f - (sz.height - frameSz.height)*pos.y;
	}

	if (!CCPoint::CCPointEqualToPoint(_scrollableArea->getPosition(), newPos))
	{
		_scrollableArea->setPosition(newPos);
		onMoveScrollableArea();
	}
}

/////////////////////////////////////////////////////
// public Cocos2d interface

void CEScrollView::registerWithTouchDispatcher()
{
	CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, _touchPriority, true);
}

void CEScrollView::setTouchPriority(int newPriority)
{
	_touchPriority = newPriority;
	if (CCTouchDispatcher::sharedDispatcher()->findHandler(this) != NULL)
	{
		this->setIsTouchEnabled(false);
		this->setIsTouchEnabled(true);
	}
}

void CEScrollView::setRotation(float fRotation)
{
	CCAssert(false, "CENodeScissored::setRotation: CENodeScissored node can't be rotated!");
}

CCSize CEScrollView::calculateFrameSizeForNewContentSize(CCSize newContentSize)
{
	if (_insideScrollbar)
		return newContentSize;

	if (_horizontalScrolling && _horizontalScrollBar != NULL)
		newContentSize.height -= _horizontalScrollBar->getContentSize().width;
	if (_verticalScrolling && _verticalScrollBar != NULL)
		newContentSize.width -= _verticalScrollBar->getContentSize().width;

	return newContentSize;
}

void CEScrollView::setContentSize(const CCSize& contentSize)
{
	CCLayer::setContentSize(contentSize);

	if (_frame != NULL)
	{
		CCSize oldFrameSz = _frame->getContentSize();
		CCSize szFrame = calculateFrameSizeForNewContentSize(contentSize);
		_frame->setContentSize(szFrame);

		float allignX = 0.f;
		switch (_saaX)
		{
		case eCE_SAA_X_left: allignX = 0.f; break;
		case eCE_SAA_X_center: allignX = (szFrame.width - oldFrameSz.width)/2.f; break;
		case eCE_SAA_X_right: allignX = szFrame.width - oldFrameSz.width; break;
		}
		float allignY = 0.f;
		switch (_saaY)
		{
		case eCE_SAA_Y_bottom: allignY = 0.f; break;
		case eCE_SAA_Y_center: allignY = (szFrame.height - oldFrameSz.height)/2.f; break;
		case eCE_SAA_Y_top: allignY = szFrame.height - oldFrameSz.height; break;
		}
		
		CCPoint pos(allignX + _scrollableArea->getPosition().x, allignY + _scrollableArea->getPosition().y);
		
		//Correct position
		CCSize szArea = _scrollableArea->getContentSize();
		if (pos.x + szArea.width/2.f < szFrame.width)
			pos.x = szFrame.width - szArea.width/2.f;
		else if (pos.x - szArea.width/2.f > 0.f)
			pos.x = szArea.width/2.f;
		if (pos.y + szArea.height/2.f < szFrame.height)
			pos.y = szFrame.height - szArea.height/2.f;
		else if (pos.y - szArea.height/2.f > 0.f)
			pos.y = szArea.height/2.f;

		_scrollableArea->setPosition(pos);


		if (_background != NULL)
			_background->setContentSize(this->getContentSize());

		float horW = 0.f;
		if (_horizontalScrolling && _horizontalScrollBar != NULL)
		{
			horW = _horizontalScrollBar->getContentSize().width;
			_horizontalScrollBar->setContentSize(CCSize(horW, _frame->getContentSize().width));
		}

		if (_verticalScrolling && _verticalScrollBar != NULL)
		{
			_verticalScrollBar->setPosition(ccp(this->getContentSize().width - _verticalScrollBar->getContentSize().width, horW));
			_verticalScrollBar->setContentSize(CCSize(_verticalScrollBar->getContentSize().width, _frame->getContentSize().height));
		}
		onChangeScrollableArea();
	}
}


//////////////////////////////////////////////////////
// Touch processing

bool CEScrollView::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
	if (_currentTouch != NULL || !isNodeContainsTouch(*this, pTouch))
		return false;

		// Set timers
	_latestTime = _accumulatedTime;
	_touchBeginTime = _accumulatedTime;
		//clear flags
	_isMovedOnLatestTouchMove = false;
	_areScrollBarsShown = false;
		//Clear speed accumulator
	for (unsigned int i = 0; i < CE_SCROLLVIEW_MOVE_FILTER_SIZE; ++i)
	{
		_speedAccumulator[i].x = 0;
		_speedAccumulator[i].y = 0;
	}
	_accumulatorCursor = 0;

	_currentTouch = pTouch;
	_touchBeginPoint = pTouch->locationInView(pTouch->view());
	_latestTouchMovePoint = CCDirector::sharedDirector()->convertToGL(_touchBeginPoint);

	_touchBeginAreaPos = _scrollableArea->getPosition();
	_touchMoveAreaPos = _scrollableArea->getPosition();

	return true;
}

void CEScrollView::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
	if (_accumulatedTime - _latestTime < FLT_EPSILON)
		return;
	CCPoint newPos = calculateNewPosition(pTouch);
	_isMovedOnLatestTouchMove = !CCPoint::CCPointEqualToPoint(_scrollableArea->getPosition(), newPos);
	if (_isMovedOnLatestTouchMove)
	{
		if (_accumulatedTime - _latestTime > CE_SCROLLVIEW_MOVE_CLEAR_FILTER_TIME)
		{
			// Clear speed accumulator
			for (unsigned int i = 0; i < CE_SCROLLVIEW_MOVE_FILTER_SIZE; ++i)
			{
				_speedAccumulator[i].x = 0;
				_speedAccumulator[i].y = 0;
			}
			_accumulatorCursor = 0;
			//Clear speed vector
			_speedVector.x = 0.f;
			_speedVector.y = 0.f;
		}

		_speedAccumulator[_accumulatorCursor].x = (newPos.x - _scrollableArea->getPosition().x)/(_accumulatedTime - _latestTime);
		_speedAccumulator[_accumulatorCursor].y = (newPos.y - _scrollableArea->getPosition().y)/(_accumulatedTime - _latestTime);
		++_accumulatorCursor;
		if (_accumulatorCursor == CE_SCROLLVIEW_MOVE_FILTER_SIZE)
			_accumulatorCursor = 0;

		_latestTime = _accumulatedTime;
		_scrollableArea->setPosition(newPos);
		onMoveScrollableArea();
	}
	_touchMoveAreaPos = _scrollableArea->getPosition();
}

void CEScrollView::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{	
	//Do latest move in case when onMove was skipped by the system
	CCPoint newPos = calculateNewPosition(pTouch);
	if (!CCPoint::CCPointEqualToPoint(_scrollableArea->getPosition(), newPos) &&
		_accumulatedTime - _latestTime > FLT_EPSILON)
	{
		_speedAccumulator[_accumulatorCursor].x = (newPos.x - _scrollableArea->getPosition().x)/(_accumulatedTime - _latestTime);
		_speedAccumulator[_accumulatorCursor].y = (newPos.y - _scrollableArea->getPosition().y)/(_accumulatedTime - _latestTime);

		_scrollableArea->setPosition(newPos);
		onMoveScrollableArea();
	}

	_touchMoveAreaPos = _scrollableArea->getPosition();

	validateScrollableAreaPosition();

	CCLayer::ccTouchEnded(pTouch, pEvent);

	// If we move
	if (_accumulatedTime - _latestTime < CE_SCROLLVIEW_END_CLEAR_FILTER_TIME &&
		!CCPoint::CCPointEqualToPoint(_touchBeginPoint, pTouch->locationInView(pTouch->view())))
	{
		CCPoint oldSpeedVector = _speedVector;
		float currentSpeed = 0;
		float oldSpeedBase = ccpLength(_speedVector);
		if (_touchEndTime > FLT_EPSILON)
			currentSpeed = oldSpeedBase - ccpLength(_accelVector)*(_accumulatedTime - _touchEndTime);

		//Calculate new speed vector
		_speedVector.x = 0.f;
		_speedVector.y = 0.f;
		unsigned int counter = 0;
		for (unsigned int i = 0; i < CE_SCROLLVIEW_MOVE_FILTER_SIZE; ++i)
		{
			_speedVector.x += _speedAccumulator[i].x;
			_speedVector.y += _speedAccumulator[i].y;
			if (fabs(_speedAccumulator[i].x) > FLT_EPSILON || fabs(_speedAccumulator[i].y) > FLT_EPSILON)
				++counter;
		}

		if (counter != 0)
		{
			_speedVector.x /= (float)counter;
			_speedVector.y /= (float)counter;
			float newSpeed = ccpLength(_speedVector);
			_speedVector = ccpNormalize(_speedVector);
			if (newSpeed > currentSpeed)
			{
				// Reset moving parameters 
				if (newSpeed > CE_SCROLLVIEW_MAX_SPEED)
					newSpeed = CE_SCROLLVIEW_MAX_SPEED;
				float acceleration = -newSpeed*(CE_SCROLLVIEW_ACCEL_MUL_FOR_MIN_SPEED + 
					(CE_SCROLLVIEW_ACCEL_MUL_FOR_MAX_SPEED - CE_SCROLLVIEW_ACCEL_MUL_FOR_MIN_SPEED)*newSpeed/CE_SCROLLVIEW_MAX_SPEED);
				_accelVector = ccpMult(_speedVector, acceleration);
				_speedVector = ccpMult(_speedVector, newSpeed);
				_touchEndTime = _accumulatedTime;
				_startPoint = _scrollableArea->getPosition();
			}
			else
			{
				//Restore old speed
				_speedVector = oldSpeedVector;
			}
		}
		else
		{		
			//Clear speed vector and stop current moving
			_speedVector.x = 0.f;
			_speedVector.y = 0.f;
			_touchEndTime = 0.f;
		};
	}
	else
	{
		//Clear speed vector and stop current moving
		_speedVector.x = 0.f;
		_speedVector.y = 0.f;
		_touchEndTime = 0.f;
	}

	// If we have hidden scrollbar and moving is stopped, hide scrollbars
	if (_hiddenScrollbar && _touchEndTime < FLT_EPSILON)
	{
		if (_horizontalScrollBar != NULL)
			_horizontalScrollBar->hide();
		if (_verticalScrollBar != NULL)
			_verticalScrollBar->hide();
	}

	_currentTouch = NULL;
}

void CEScrollView::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent)
{
	CCLayer::ccTouchCancelled(pTouch, pEvent);

	_currentTouch = NULL;
	if (_horizontalScrolling && _horizontalScrollBar != NULL)
		_horizontalScrollBar->hide();
	if (_verticalScrolling && _verticalScrollBar != NULL)
		_verticalScrollBar->hide();
}

//////////////////////////////////////////////////////
// Protected interface

void CEScrollView::updateTime(ccTime dt)
{
	_accumulatedTime += dt;

// Update position of scrollable area (self moving)
	_isSelfMoving = _touchEndTime > FLT_EPSILON &&
					_currentTouch == NULL && 
					_accumulatedTime - _touchEndTime > FLT_EPSILON;

	if (_isSelfMoving)
	{
		float t = _accumulatedTime - _touchEndTime;
		CCPoint newPos = _scrollableArea->getPosition();
		CCSize frameSz = _frame->getContentSize();
		CCSize sz = _scrollableArea->getContentSize();
		if (_horizontalScrolling && sz.width > frameSz.width)
		{
			newPos.x = _startPoint.x + t*_speedVector.x + _accelVector.x*t*t/2.f;

			if (newPos.x > sz.width/2.f)
				newPos.x = sz.width/2.f;
			else if (newPos.x < frameSz.width - sz.width/2.f)
				newPos.x = frameSz.width - sz.width/2.f;
		}
		if (_verticalScrolling && sz.height > frameSz.height)
		{
			newPos.y = _startPoint.y + t*_speedVector.y + _accelVector.y*t*t/2.f;

			if (newPos.y > sz.height/2.f)
				newPos.y = sz.height/2.f;
			else if (newPos.y < frameSz.height - sz.height/2.f)
				newPos.y = frameSz.height - sz.height/2.f;
		}
		if (fabs(_speedVector.x) - fabs(_accelVector.x)*t < CE_SCROLLVIEW_MIN_SPEED && 
			fabs(_speedVector.y) - fabs(_accelVector.y)*t < CE_SCROLLVIEW_MIN_SPEED)
		{
			//Stop moving
			_touchEndTime = 0.f;
			if (_hiddenScrollbar)
			{
				if (_horizontalScrollBar != NULL)
					_horizontalScrollBar->hide();
				if (_verticalScrollBar != NULL)
					_verticalScrollBar->hide();
			}
		}

		if (!CCPoint::CCPointEqualToPoint(_scrollableArea->getPosition(), newPos))
		{
			_scrollableArea->setPosition(newPos);
			onMoveScrollableArea();
		}
		else
			_touchEndTime = 0.f;
	}

	//Update scrollbar visibiity
	if (_hiddenScrollbar && 
		!_areScrollBarsShown &&
		(_isMovedOnLatestTouchMove || _isSelfMoving))
	{
		_areScrollBarsShown = true;
		if (_horizontalScrolling && _horizontalScrollBar != NULL)
			_horizontalScrollBar->show();
		if (_verticalScrolling && _verticalScrollBar != NULL)
			_verticalScrollBar->show();
	}
}

void CEScrollView::doSetIsEnabled(bool isEnabled)
{
	CCLayer::setIsTouchEnabled(isEnabled);
}

void CEScrollView::onChangeScrollableArea()
{
	if (_horizontalScrolling && _horizontalScrollBar != NULL && _scrollableArea->getContentSize().width > 0.f)
		_horizontalScrollBar->setBarSize(_frame->getContentSize().width/_scrollableArea->getContentSize().width);

	if (_verticalScrolling && _verticalScrollBar != NULL && _scrollableArea->getContentSize().height > 0.f)
		_verticalScrollBar->setBarSize(_frame->getContentSize().height/_scrollableArea->getContentSize().height);

	onMoveScrollableArea();
}

void CEScrollView::onMoveScrollableArea()
{
	CCSize frameSz = _frame->getContentSize();
	CCSize sz = _scrollableArea->getContentSize();
	CCPoint newPos = _scrollableArea->getPosition();

	if (_horizontalScrolling && _horizontalScrollBar != NULL)
	{
		if (sz.width > frameSz.width)
			_horizontalScrollBar->setBarPosition((sz.width/2.f - newPos.x)/(sz.width - frameSz.width));
		else
			_horizontalScrollBar->setBarPosition(0.f);
	}
	if (_verticalScrolling && _verticalScrollBar != NULL)
	{
		if (sz.height > frameSz.height)
			_verticalScrollBar->setBarPosition(1.f - (sz.height/2.f - newPos.y)/(sz.height - frameSz.height));
		else
			_verticalScrollBar->setBarPosition(0.f);
	}
}

CCPoint CEScrollView::calculateNewPosition(cocos2d::CCTouch *pTouch)
{
	CCPoint delta;
	CCPoint current = pTouch->locationInView(pTouch->view());
	current = CCDirector::sharedDirector()->convertToGL(current);
	delta.x = current.x - _latestTouchMovePoint.x;
	delta.y = current.y - _latestTouchMovePoint.y;
	_latestTouchMovePoint = current;

	CCSize frameSz = _frame->getContentSize();
	CCSize sz = _scrollableArea->getContentSize();
	CCPoint newPos = _scrollableArea->getPosition();

	if (_horizontalScrolling && sz.width > frameSz.width)
	{
		newPos.x += delta.x;
		if (newPos.x > sz.width/2.f)
		{
			newPos.x -= delta.x*(1.f - CE_SCROLLVIEW_RUBBER_UPDATE_POS_K);
		}
		else if (newPos.x < frameSz.width - sz.width/2.f)
		{
			newPos.x -= delta.x*(1.f - CE_SCROLLVIEW_RUBBER_UPDATE_POS_K);
		}
	}
	if (_verticalScrolling && sz.height > frameSz.height)
	{
		newPos.y += delta.y;
		if (newPos.y > sz.height/2.f)
		{
			newPos.y -= delta.y*(1.f - CE_SCROLLVIEW_RUBBER_UPDATE_POS_K);
		}
		else if (newPos.y < frameSz.height - sz.height/2.f)
		{
			newPos.y -= delta.y*(1.f - CE_SCROLLVIEW_RUBBER_UPDATE_POS_K);
		}
	}
	return newPos;
}

void CEScrollView::validateScrollableAreaPosition()
{
	CCPoint pos = _scrollableArea->getPosition();
	CCSize frameSz = _frame->getContentSize();
	CCSize sz = _scrollableArea->getContentSize();
	if (_horizontalScrolling && sz.width > frameSz.width)
	{
		if (pos.x > sz.width/2.f)
			pos.x = sz.width/2.f;
		else if (pos.x < frameSz.width - sz.width/2.f)
			pos.x = frameSz.width - sz.width/2.f;
	}
	if (_verticalScrolling && sz.height > frameSz.height)
	{
		if (pos.y > sz.height/2.f)
			pos.y = sz.height/2.f;
		else if (pos.y < frameSz.height - sz.height/2.f)
			pos.y = frameSz.height - sz.height/2.f;
	}
	if (!CCPoint::CCPointEqualToPoint(_scrollableArea->getPosition(), pos))
	{
		_scrollableArea->setPosition(pos);
		onMoveScrollableArea();
	}
}

}; // end namespace cocosext

